2 * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
23 Change History (most recent first):
25 $Log: Mac\040OS\040Test\040Searcher.c,v $
26 Revision 1.21 2004/12/16 20:49:34 cheshire
27 <rdar://problem/3324626> Cache memory management improvements
29 Revision 1.20 2004/10/19 21:33:18 cheshire
30 <rdar://problem/3844991> Cannot resolve non-local registrations using the mach API
31 Added flag 'kDNSServiceFlagsForceMulticast'. Passing through an interface id for a unicast name
32 doesn't force multicast unless you set this flag to indicate explicitly that this is what you want
34 Revision 1.19 2004/09/17 01:08:50 cheshire
35 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
36 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
37 declared in that file are ONLY appropriate to single-address-space embedded applications.
38 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
40 Revision 1.18 2004/09/16 21:59:16 cheshire
41 For consistency with zerov6Addr, rename zeroIPAddr to zerov4Addr
43 Revision 1.17 2004/06/10 04:37:27 cheshire
44 Add new parameter in mDNS_GetDomains()
46 Revision 1.16 2004/03/12 21:30:25 cheshire
47 Build a System-Context Shared Library from mDNSCore, for the benefit of developers
48 like Muse Research who want to be able to use mDNS/DNS-SD from GPL-licensed code.
50 Revision 1.15 2004/01/24 23:55:15 cheshire
51 Change to use mDNSOpaque16fromIntVal/mDNSVal16 instead of shifting and masking
53 Revision 1.14 2003/11/14 21:27:09 cheshire
54 <rdar://problem/3484766>: Security: Crashing bug in mDNSResponder
55 Fix code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1005) instead of 256-byte buffers.
57 Revision 1.13 2003/08/14 02:19:54 cheshire
58 <rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
60 Revision 1.12 2003/08/12 19:56:24 cheshire
65 #include <stdio.h> // For printf()
66 #include <Events.h> // For WaitNextEvent()
67 #include <SIOUX.h> // For SIOUXHandleOneEvent()
69 #include "mDNSEmbeddedAPI.h" // Defines the interface to the client layer above
70 #include "mDNSMacOS9.h" // Defines the specific types needed to run mDNS on this platform
74 OTLIFO serviceinfolist
;
75 Boolean headerPrinted
;
79 typedef struct { ServiceInfo i
; mDNSBool add
; mDNSBool dom
; OTLink link
; } linkedServiceInfo
;
81 // These don't have to be globals, but their memory does need to remain valid for as
82 // long as the search is going on. They are declared as globals here for simplicity.
83 #define RR_CACHE_SIZE 1000
84 static CacheEntity rrcachestorage
[RR_CACHE_SIZE
];
85 static mDNS mDNSStorage
;
86 static mDNS_PlatformSupport PlatformSupportStorage
;
87 static SearcherServices services
;
88 static DNSQuestion browsequestion
, domainquestion
;
90 // PrintServiceInfo prints the service information to standard out
91 // A real application might want to do something else with the information
92 static void PrintServiceInfo(SearcherServices
*services
)
94 OTLink
*link
= OTReverseList(OTLIFOStealList(&services
->serviceinfolist
));
98 linkedServiceInfo
*ls
= OTGetLinkObject(link
, linkedServiceInfo
, link
);
99 ServiceInfo
*s
= &ls
->i
;
101 if (!services
->headerPrinted
)
103 printf("%-55s Type Domain IP Address Port Info\n", "Name");
104 services
->headerPrinted
= true;
109 char c_dom
[MAX_ESCAPED_DOMAIN_NAME
];
110 ConvertDomainNameToCString(&s
->name
, c_dom
);
111 if (ls
->add
) printf("%-55s available for browsing\n", c_dom
);
112 else printf("%-55s no longer available for browsing\n", c_dom
);
117 domainname type
, domain
;
118 char c_name
[MAX_DOMAIN_LABEL
+1], c_type
[MAX_ESCAPED_DOMAIN_NAME
], c_dom
[MAX_ESCAPED_DOMAIN_NAME
], c_ip
[20];
119 DeconstructServiceName(&s
->name
, &name
, &type
, &domain
);
120 ConvertDomainLabelToCString_unescaped(&name
, c_name
);
121 ConvertDomainNameToCString(&type
, c_type
);
122 ConvertDomainNameToCString(&domain
, c_dom
);
123 sprintf(c_ip
, "%d.%d.%d.%d", s
->ip
.ip
.v4
.b
[0], s
->ip
.ip
.v4
.b
[1], s
->ip
.ip
.v4
.b
[2], s
->ip
.ip
.v4
.b
[3]);
125 printf("%-55s %-16s %-14s ", c_name
, c_type
, c_dom
);
126 if (ls
->add
) printf("%-15s %5d %#s\n", c_ip
, mDNSVal16(s
->port
), s
->TXTinfo
);
127 else printf("Removed\n");
135 // When the name, address, port, and txtinfo for a service is found, FoundInstanceInfo()
136 // enqueues a record for PrintServiceInfo() to print.
137 // Note, a browsing application would *not* normally need to get all this information --
138 // all it needs is the name, to display to the user.
139 // Finding out the address, port, and txtinfo should be deferred to the time that the user
140 // actually needs to contact the service to use it.
141 static void FoundInstanceInfo(mDNS
*const m
, ServiceInfoQuery
*query
)
143 SearcherServices
*services
= (SearcherServices
*)query
->ServiceInfoQueryContext
;
144 linkedServiceInfo
*info
= (linkedServiceInfo
*)(query
->info
);
145 if (query
->info
->ip
.type
== mDNSAddrType_IPv4
)
147 mDNS_StopResolveService(m
, query
); // For this test code, one answer is sufficient
148 OTLIFOEnqueue(&services
->serviceinfolist
, &info
->link
);
153 // When a new named instance of a service is found, FoundInstance() is called.
154 // In this sample code we turn around and immediately issue a query to resolve that service name to
155 // find its address, port, and txtinfo, but a normal browing application would just display the name.
156 static void FoundInstance(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
)
158 #pragma unused (question)
159 SearcherServices
*services
= (SearcherServices
*)question
->QuestionContext
;
160 linkedServiceInfo
*info
;
162 debugf("FoundInstance %##s PTR %##s", answer
->name
->c
, answer
->rdata
->u
.name
.c
);
164 if (answer
->rrtype
!= kDNSType_PTR
) return;
165 if (!services
) { debugf("FoundInstance: services is NULL"); return; }
167 info
= (linkedServiceInfo
*)OTAllocMem(sizeof(linkedServiceInfo
));
168 if (!info
) { services
->lostRecords
= true; return; }
170 info
->i
.name
= answer
->rdata
->u
.name
;
171 info
->i
.InterfaceID
= answer
->InterfaceID
;
172 info
->i
.ip
.type
= mDNSAddrType_IPv4
;
173 info
->i
.ip
.ip
.v4
= zerov4Addr
;
174 info
->i
.port
= zeroIPPort
;
175 info
->add
= AddRecord
;
176 info
->dom
= mDNSfalse
;
178 if (!AddRecord
) // If TTL == 0 we're deleting a service,
179 OTLIFOEnqueue(&services
->serviceinfolist
, &info
->link
);
180 else // else we're adding a new service
182 ServiceInfoQuery
*q
= (ServiceInfoQuery
*)OTAllocMem(sizeof(ServiceInfoQuery
));
183 if (!q
) { OTFreeMem(info
); services
->lostRecords
= true; return; }
184 mDNS_StartResolveService(m
, q
, &info
->i
, FoundInstanceInfo
, services
);
188 static void FoundDomain(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
)
191 #pragma unused (question)
192 SearcherServices
*services
= (SearcherServices
*)question
->QuestionContext
;
193 linkedServiceInfo
*info
;
195 debugf("FoundDomain %##s PTR %##s", answer
->name
->c
, answer
->rdata
->u
.name
.c
);
197 if (answer
->rrtype
!= kDNSType_PTR
) return;
198 if (!services
) { debugf("FoundDomain: services is NULL"); return; }
200 info
= (linkedServiceInfo
*)OTAllocMem(sizeof(linkedServiceInfo
));
201 if (!info
) { services
->lostRecords
= true; return; }
203 info
->i
.name
= answer
->rdata
->u
.name
;
204 info
->i
.InterfaceID
= answer
->InterfaceID
;
205 info
->i
.ip
.type
= mDNSAddrType_IPv4
;
206 info
->i
.ip
.ip
.v4
= zerov4Addr
;
207 info
->i
.port
= zeroIPPort
;
208 info
->add
= AddRecord
;
209 info
->dom
= mDNStrue
;
211 OTLIFOEnqueue(&services
->serviceinfolist
, &info
->link
);
214 // YieldSomeTime() just cooperatively yields some time to other processes running on classic Mac OS
215 static Boolean
YieldSomeTime(UInt32 milliseconds
)
217 extern Boolean SIOUXQuitting
;
219 WaitNextEvent(everyEvent
, &e
, milliseconds
/ 17, NULL
);
220 SIOUXHandleOneEvent(&e
);
221 return(SIOUXQuitting
);
227 Boolean DoneSetup
= false;
230 SIOUXSettings
.asktosaveonclose
= false;
231 SIOUXSettings
.userwindowtitle
= "\pMulticast DNS Searcher";
232 SIOUXSettings
.rows
= 40;
233 SIOUXSettings
.columns
= 132;
235 printf("Multicast DNS Searcher\n\n");
236 printf("This software reports errors using MacsBug breaks,\n");
237 printf("so if you don't have MacsBug installed your Mac may crash.\n\n");
238 printf("******************************************************************************\n");
240 err
= InitOpenTransport();
241 if (err
) { debugf("InitOpenTransport failed %d", err
); return(err
); }
243 err
= mDNS_Init(&mDNSStorage
, &PlatformSupportStorage
, rrcachestorage
, RR_CACHE_SIZE
,
244 mDNS_Init_DontAdvertiseLocalAddresses
, mDNS_Init_NoInitCallback
, mDNS_Init_NoInitCallbackContext
);
245 if (err
) return(err
);
247 // Make sure OT has a large enough memory pool for us to draw from at OTNotifier (interrupt) time
248 tempmem
= OTAllocMem(0x10000);
249 if (tempmem
) OTFreeMem(tempmem
);
250 else printf("**** Warning: OTAllocMem couldn't pre-allocate 64K for us.\n");
252 services
.serviceinfolist
.fHead
= NULL
;
253 services
.headerPrinted
= false;
254 services
.lostRecords
= false;
256 while (!YieldSomeTime(35))
258 #if MDNS_ONLYSYSTEMTASK
259 // For debugging, use "#define MDNS_ONLYSYSTEMTASK 1" and call mDNSPlatformIdle() periodically.
260 // For shipping code, don't define MDNS_ONLYSYSTEMTASK, and you don't need to call mDNSPlatformIdle()
261 extern void mDNSPlatformIdle(mDNS
*const m
);
262 mDNSPlatformIdle(&mDNSStorage
); // Only needed for debugging version
264 if (mDNSStorage
.mDNSPlatformStatus
== mStatus_NoError
&& !DoneSetup
)
266 domainname srvtype
, srvdom
;
268 printf("\nSending mDNS service lookup queries and waiting for responses...\n\n");
269 MakeDomainNameFromDNSNameString(&srvtype
, "_http._tcp.");
270 MakeDomainNameFromDNSNameString(&srvdom
, "local.");
271 err
= mDNS_StartBrowse(&mDNSStorage
, &browsequestion
, &srvtype
, &srvdom
, mDNSInterface_Any
, mDNSfalse
, FoundInstance
, &services
);
273 err
= mDNS_GetDomains(&mDNSStorage
, &domainquestion
, mDNS_DomainTypeBrowse
, NULL
, mDNSInterface_Any
, FoundDomain
, &services
);
277 if (services
.serviceinfolist
.fHead
)
278 PrintServiceInfo(&services
);
280 if (services
.lostRecords
)
282 services
.lostRecords
= false;
283 printf("**** Warning: Out of memory: Records have been missed.\n");
287 mDNS_StopBrowse(&mDNSStorage
, &browsequestion
);
288 mDNS_Close(&mDNSStorage
);